package es.ugr.beequizz.dao.impl;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;

import es.ugr.beequizz.bean.PreguntaBean;
import es.ugr.beequizz.bean.ValidacionBean;
import es.ugr.beequizz.dao.GenericDAO;
import es.ugr.beequizz.dao.PreguntaDAO;
import es.ugr.beequizz.model.Pregunta;
import es.ugr.beequizz.model.Usuario;

@Repository
public class PreguntaDAOImpl extends GenericDAO implements PreguntaDAO{

	// Requete SQL para guardar la pregunta
	private static final String INCLUIR_PREGUNTA_SQL = "INSERT INTO pregunta ( asignatura_id, " +
			" dificultad_id, creador_id, fecha_creacion, fecha_modificacion, enunciado, valida) " +
			" VALUES ( :asignatura_id , " +
			" :dificultad_id, :creador_id, :fecha_creacion, :fecha_modificacion, :enunciado, FALSE) RETURNING id"; 
	
	// Requete SQL para recuperar las preguntas expecificando la asigntura y el nivel
	private static final String BUSCAR_PREGUNTA_SQL = "SELECT pregunta.id, pregunta.enunciado, pregunta.puntuacion, pregunta.valida, usuario.nombre, usuario.apellidos   FROM pregunta " +
			"INNER JOIN usuario ON (pregunta.creador_id = usuario.id) " +
			"WHERE asignatura_id = :asignatura_id AND dificultad_id = :dificultad_id";
	
	// Requete SQL para recuperar las preguntas expecificando la asigntura y el nivel
	private static final String RECUPERAR_PREGUNTA_SQL = "SELECT * FROM pregunta WHERE id = :id";
	
	/*Requete para suprimir una pregunta especificado la id de la pregunta*/
	private static final String SUPRIMIR_PREGUNTA_SQL = "DELETE FROM pregunta WHERE id = :preguntaId";
	
	/*Requete para recuperar un numero de preguntas determinadas de forma aleatoria*/
	private static final String PREGUNTA_ALEATORIA_SQL = "SELECT * FROM pregunta WHERE valida IS TRUE AND asignatura_id =:asignatura_id "
			+ " AND dificultad_id =:dificultad_id ORDER BY random() LIMIT :numPreguntas";
	
	/*Requete para recuperar el contenido de una pregunta a partir de la id*/
	private static final String CONTENIDO_PREGUNTA_SQL = "SELECT * FROM pregunta WHERE id = :pregunta_id";
	
	/*Demanda SQL para recuperar las ids de las preguntas asociadas a una partida en concreto*/
	private static final String  IDS_PREGUNTAS_PARTIDA_SQL = "SELECT pregunta_id FROM preguntas_partida WHERE partida_id = :partidaId";
	
	/*Demanda SQL para recuperar una pregunta que el jugador no haya contestado */
	private static final String UNA_PREGUNTA_SQL = " SELECT id FROM pregunta WHERE  valida IS TRUE AND id NOT IN (SELECT pregunta_id FROM preguntas_partida WHERE partida_id = :partidaId"+
			" AND usuario_id = :usuarioId) AND asignatura_id = :asignaturaId AND dificultad_id = :dificultadId ORDER BY random() LIMIT 1";
	
	private static final String MODIFICAR_PREGUNTA_SQL = " UPDATE pregunta SET (asignatura_id, dificultad_id,fecha_modificacion, enunciado) = (:asignaturaId, :dificultadId, :fecha_modificacion,:enunciado) WHERE id = :id";

	private static final String VALIDACION_PREGUNTA_SQL = " UPDATE pregunta SET valida = :valida WHERE id = :id";
	
	public Long incluirPregunta(PreguntaBean bean) {
		
		// Inicializacion de los parametros que vamos a guardar
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("asignatura_id", bean.getIdAsignatura());
		params.put("dificultad_id", bean.getIdDificultad());
		params.put("fecha_creacion", bean.getFecha());
		params.put("fecha_modificacion", bean.getFecha());
		params.put("creador_id", bean.getIdUsuario());
		params.put("enunciado", bean.getPregunta());

		return this.namedTemplate.queryForLong(INCLUIR_PREGUNTA_SQL, params);

		
	}

	private class PreguntaRowMapper implements RowMapper<Pregunta> {

		public Pregunta mapRow(ResultSet result, int arg1) throws SQLException {
			Pregunta pregunta = new Pregunta();
			pregunta.setId(result.getLong("id"));
			pregunta.setEnunciado(result.getString("enunciado"));
			pregunta.setPuntuacion(result.getLong("puntuacion"));
			pregunta.setValida(result.getBoolean("valida"));
			
			return pregunta;
		}
	}
	
	private class PreguntaUsuarioRowMapper implements RowMapper<Pregunta> {

		public Pregunta mapRow(ResultSet result, int arg1) throws SQLException {
			Pregunta pregunta = new Pregunta();
			pregunta.setId(result.getLong("id"));
			pregunta.setEnunciado(result.getString("enunciado"));
			pregunta.setPuntuacion(result.getLong("puntuacion"));
			pregunta.setValida(result.getBoolean("valida"));
			
			Usuario usuario = new Usuario();
			usuario.setNombre(result.getString("nombre"));
			usuario.setApellidos(result.getString("apellidos"));
			pregunta.setCreador(usuario);
			return pregunta;
		}
	}
	
	private class PreguntaBeanRowMapper implements RowMapper<PreguntaBean> {

		public PreguntaBean mapRow(ResultSet result, int arg1) throws SQLException {
			PreguntaBean pregunta = new PreguntaBean();
			pregunta.setId(result.getLong("id"));
			pregunta.setPregunta(result.getString("enunciado"));
			pregunta.setPuntacion(result.getLong("puntuacion"));
			pregunta.setIdAsignatura(result.getLong("asignatura_id"));
			pregunta.setIdDificultad(result.getLong("dificultad_id"));
			pregunta.setIdUsuario(result.getLong("creador_id"));
			
			return pregunta;
		}
	}


	
	public List<Pregunta> recuperarPreguntas(Long asignaturaId,Long dificultadId) {
		
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("asignatura_id", asignaturaId);
		params.put("dificultad_id", dificultadId);
		
		
		return this.namedTemplate.query(BUSCAR_PREGUNTA_SQL, params, new PreguntaUsuarioRowMapper());
	}

	public void suprimirPregunta(Long id) {
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("preguntaId", id);
		
		this.namedTemplate.update(SUPRIMIR_PREGUNTA_SQL, params);
		
	}

	public List<Pregunta> recuperarListaPreguntas(int numPreguntas,
			Long asignaturaId, Long dificultadId) {
		
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("asignatura_id", asignaturaId);
		params.put("dificultad_id", dificultadId);
		params.put("numPreguntas", numPreguntas);
		
		return this.namedTemplate.query(PREGUNTA_ALEATORIA_SQL, params, new PreguntaRowMapper());
	}

	public Pregunta recuperarContenidoPreguntas(Long preguntaId) {
	
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("pregunta_id", preguntaId);
		
		return this.namedTemplate.queryForObject(CONTENIDO_PREGUNTA_SQL, params, new PreguntaRowMapper());
	}

	public List<Long> recuperarListaPreguntasPartida(Long partidaId) {
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("partidaId", partidaId);
		
		return this.namedTemplate.queryForList(IDS_PREGUNTAS_PARTIDA_SQL, params, Long.class);
	}

	public Long recuperarUnaPregunta(Long partidaId, Long asignaturaId, Long dificultadId, Long usuarioId) {
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("partidaId", partidaId);
		params.put("usuarioId", usuarioId);
		params.put("asignaturaId", asignaturaId);
		params.put("dificultadId", dificultadId);
		try {
			return namedTemplate.queryForLong(UNA_PREGUNTA_SQL, params);
		} catch (EmptyResultDataAccessException e) {
			return  null;
		}
	}

	public PreguntaBean recuperarPregunta(Long preguntaId) {
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("id", preguntaId);
		return namedTemplate.queryForObject(RECUPERAR_PREGUNTA_SQL, params, new PreguntaBeanRowMapper());
	}

	public void modificarPregunta(PreguntaBean pregunta) {
		// Inicializacion de los parametros que vamos a guardar
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("id", pregunta.getId());
		params.put("asignaturaId", pregunta.getIdAsignatura());
		params.put("dificultadId", pregunta.getIdDificultad());
		params.put("fecha_modificacion", new Date());
		params.put("enunciado", pregunta.getPregunta());

		this.namedTemplate.update(MODIFICAR_PREGUNTA_SQL, params);
		
	}

	public void validacionPregunta(ValidacionBean bean) {
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("id", bean.getId());
		params.put("valida", bean.isValido());
		
		this.namedTemplate.update(VALIDACION_PREGUNTA_SQL, params);
	}
	


}
